简书链接:原创andorid最方便定制的新手引导浮层新手引导指引页半透明挖空制作与开源github以及分享实现思路
文章字数:705,阅读全文大约需要2分钟
首先文章非常简单,代码非常精简,也就是说这里的技术只是打造一个非常方便扩展的view,剩下的事情没有学习成本,只需要跟平常开发一样写布局摆放到指定位置就行,越是精简越是非常容易扩展,整个引导浮层就镂空区域没法使用现成view,或者xml写出来的。

设计思路和扩展原理

1、引导箭头是自己摆放,方便用户定制,自己用布局嵌套就好
2、方便用户随意摆放到任何位置,如对话框、顶层decorview或者放置到fragment里面于是我打算设计成一个view,而不是一个封装死的框架.而且这个view只处理镂空形状问题.
3、镂空形状的设计要方便扩展,我采取接口的方式传递画板和画笔 默认实现了圆形和矩形,用户可以轻松实现其他形状定制。

镂空实现原理

超级简单的,我之前看了别人那个就头疼,于是自己着手写了一个镂空的,采用的绘制模式是`

1
2
3
4
5
6
7
8
9
10
11
![image.png](https://upload-images.jianshu.io/upload_images/2815884-0a3ad00c096942e6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/600)

首先要说明白一点就是```det```表示底层图层, ```src```表示顶层的图层
从图中得知```,dstout```模式 就是把```src```盖到```dstout```的右下角,导致右下角消失不见了。

所以我这里是绘制了一个矩形半透明 然后上层 绘制一个要镂空的任意形状, 颜色随便,我这里保持不变。

开源完整地址

https://github.com/qssq/HollowOutView
导入依赖

compile ‘cn.qssq666:hollowoutview:0.1’

1
使用方法

HollowOutView hollowOutView = (HollowOutView) findViewById(R.id.hollowoutview);
//在中心点100的区域绘制一个50px大小的圆圈 透明区域
HollowOutView.CiceleHollowedShapeInfo circle=new HollowOutView.CiceleHollowedShapeInfo().setCx(100).setCy(100).setRadius(100);
hollowOutView.addGuideDrawInfo(circle);
//添加一个矩形 镂空透明区域 所有单位都是px,自己转换
HollowOutView.RectHollowedShapeInfo rect=new HollowOutView.RectHollowedShapeInfo().setHeight(100).setWidth(90).setLeft(400).setTop(800);
hollowOutView.addGuideDrawInfo(rect);
hollowOutView.applyChanage();

1
2
非完整代码 ```HollowOutView ```镂空view代码如下.

/**

*/
public class HollowedOutView extends View {

public Paint getPaint() {
    return paint;
}

private Paint paint;

public HollowedOutView(Context context) {
    super(context);
    init(context);
}

public HollowedOutView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

protected void init(Context context) {


    paint = new Paint();
    paint.setFlags(Paint.ANTI_ALIAS_FLAG);
    paint.setColor(Color.parseColor("#7f000000"));//百分之50
    paint.setColor(Color.parseColor("#32000000"));//百分之20
    paint.setColor(Color.parseColor("#c8000000"));//百分之80
    setLayerType(LAYER_TYPE_SOFTWARE, null);//关闭硬件加速

}

public HollowedOutView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.drawRect(0, 0, getWidth(), getHeight(), paint);

    Xfermode mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);//从绘制模式图片得知 这种模式会导致挖空的区域消失
    paint.setXfermode(mXfermode);
    for (int i = 0; i < infos.size(); i++) {

        HollowedOutShapeInfoI guideDrawInfo = infos.get(i);
        guideDrawInfo.executeDraw(canvas, paint);

    }
    paint.setXfermode(null);


}

protected List<HollowedOutShapeInfoI> infos = new ArrayList<>();

public void addGuideDrawInfo(HollowedOutShapeInfoI info) {

}

public void addGuideDrawInfos(List<HollowedOutShapeInfoI> infos) {
    this.infos.addAll(infos);

}

public void clearGuideDrawInfo() {

    infos.clear();
}

/**
 * 镂空形状接口 可用户自定义
 */
public interface HollowedOutShapeInfoI {
    /**
     * 要挖空的形状
     *
     * @param canvas
     * @param paint
     */
    void executeDraw(Canvas canvas, Paint paint);
}

public static class RectHollowedShapeInfo implements HollowedOutShapeInfoI {


    public int getLeft() {
        return left;
    }

    public void setLeft(int left) {
        this.left = left;
    }

    public int getTop() {
        return top;
    }

    public void setTop(int top) {
        this.top = top;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    int left;
    int top;
    int width;
    int height;

    @Override
    public void executeDraw(Canvas canvas, Paint paint) {
        canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
    }

}

//默认实现的镂空圆形图标


public static class CiceleHollowedShapeInfo implements HollowedOutShapeInfoI {

    public int getCx() {
        return cx;
    }

    /**
     * 要绘制的圆圈的中心点x坐标
     *
     * @param cx
     */
    public void setCx(int cx) {
        this.cx = cx;
    }

    /**
     * 要绘制的中心点y坐标
     *
     * @return
     */
    public int getCy() {
        return cy;
    }

    public void setCy(int cy) {
        this.cy = cy;
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    int cx;
    int cy;
    /**
     * 圆角半径
     */
    int radius;

    @Override
    public void executeDraw(Canvas canvas, Paint paint) {


        canvas.drawCircle(
                cx,
                cy,
                radius, paint);
    }
    /**
     * 要挖空的形状
     *
     * @param canvas
     */
}

}